var Global = (function () {

    "use strict";

    var VENDOR_PREFIX = [ "-webkit-", "-ms-" ];
    var SCROLL_EVENTS = [];
    var RECORD_SCROLL_EVENT = null;
    var DEVICE = {
        iPhone: /iphone/i.test(window.navigator.userAgent),
        iPad: /ipad/i.test(window.navigator.userAgent),
        Android: /android/i.test(window.navigator.userAgent),
        WeChat: /micromessenger/i.test(window.navigator.userAgent)
    };

    var tweenAnimate = (function () {
        function init(options) {
            var defaults = {
                begin: null,
                end: null,
                easing: null,
                duration: null,
                update: null,
                complete: null
            };
            var setting = $.extend(defaults, options);

            return new TWEEN.Tween(setting.begin)
                   .to(setting.end, setting.duration)
                   .easing(TWEEN.Easing.Cubic[setting.easing])
                   .onUpdate(setting.update)
                   .onComplete(setting.complete)
                   .start();
        }
        function animate(time) {
            requestAnimationFrame(animate);
            TWEEN.update(time);
        }
        return {
            init: init,
            animate: animate
        }
    })();

    // 评价，星级 begin
    // :nth-child(-n+m) <m   :nth-child(n+m) >=m
    function initAppraise() {

        bindAppraiseCount();
        bindAppraiseClick();

        function bindAppraiseCount() {
            $('.list-appraise').each(function () {
                var $this = $(this);
                var $input = $($this.attr('data-input'));
                var initCount = parseInt($this.attr('data-init'));
                initCount = isNaN(initCount) ? 0 : initCount;
                $this.parent().find("li:nth-child(-n+" + initCount + ")").addClass("selected");
                $input.val(initCount);
            });
        }

        function bindAppraiseClick() {
            $(document).on("click", ".list-appraise:not(.disabled)>li", function () {
                var $this = $(this);
                var $parent = $this.closest(".list-appraise");
                if ($parent.hasClass(".disabled")) return;
                var idx = parseInt($this.index());
                var $input = $($this.closest('ul').attr('data-input'));
                $parent.find("li:nth-child(-n+" + idx + ")").addClass("selected");
                $parent.find("li:nth-child(n+" + (idx+1) + ")").removeClass("selected");
                $this.addClass("selected");
                $input.val($this.index() + 1);
            });
        }
    }
    // 评价，星级 end

    // scroll begin
    function bindBackToTop(target) {
        
        target = target || getScrollTarget();

        var stopScrollToTop = false,
            $goTop = $("#goTop");

        if ($goTop.length == 0) {
            $(target).parent().append('<div id="goTop" class="gotop" style="display:none;"></div>');
            $goTop = $("#goTop");
        }

        $goTop.click(function () {
            goTop(target, this);
        });

        bindScrollEvent(target, function (e) {
            scrollProcess(e);
        });
        scrollProcess();

        function scrollProcess(e) {
            if (!stopScrollToTop && target) {
                var $goTop = $("#goTop");
                var scrollTop = getScrollTop(target);
                if (scrollTop > 10) {
                    $goTop.show();
                } else {
                    $goTop.hide();
                }
            }
        }

        return {
            disabled: function disabledScrollToTop() {
                stopScrollToTop = true;
                $("#goTop").hide();
            },
            enabled: function enabledScrollToTop() {
                stopScrollToTop = false;
                scrollProcess();
            }
        };
    }

    function bindScrollEvent(target, handler) {

        target = target || getScrollTarget();

        var _event = null,
            hasBind = false;

        SCROLL_EVENTS.forEach(function (evt, idx) {
            if (evt.target === target) {
                hasBind = true;
                _event = evt;
                _event.handlers.push(handler);
                return;
            }
        });

        if (!_event) {
            _event = { target: target, handlers: [handler] };
            SCROLL_EVENTS.push(_event);
        }

        if (!hasBind) {
            $(_event.target).scroll(function (e) {
                _event.handlers.forEach(function (evt, idx) {
                    evt && evt(e);
                });
                //backToLimit();
                RECORD_SCROLL_EVENT && RECORD_SCROLL_EVENT(e);
            });
        }

        function backToLimit() {
            var _t = $(target)[0],
                max = _t.scrollHeight - getComputedRect(_t).height;
            if (_t.scrollTop == 0) {
                scrollTop(_t, 1);
            }
            if (_t.scrollTop == max) {
                scrollTop(_t, max-1);
            }
        }
    }

    function removeScrollEvent(target, handler) {
        SCROLL_EVENTS.forEach(function (evt, idx) {
            if (evt.target === target) {
                for (var i = 0; i < evt.handlers.length; i++) {
                    if (evt.handlers[i] === handler) {
                        evt.handlers.splice(i, 1);
                    }
                }
            }
        });
    }

    function recordScrollTop(target) {

        target = target || getScrollTarget();

        var cacheKey = location.href + "_scrollY";

        RECORD_SCROLL_EVENT = function () {
            localStorage.setItem(cacheKey, getScrollTop(target));
        };

        $(function () {
            var y = localStorage.getItem(cacheKey);
            if (y) {
                scrollTop(target, y);
            }
        });
    }

    function getScrollTarget(){
        var $target = $(document.body);
        var viewHeight = document.documentElement.clientHeight;
        if ($target[0].scrollHeight <= viewHeight){
            $target = $('[role="main"]');
        }
        return $target;
    }

    function getScrollTop(target) {
        if (target === window) {
            return window.scrollY ? window.scrollY : document.body.scrollTop;
        } else if (target) {
            return $(target)[0].scrollTop;
        }
    }

    function goTop(target, button) {
        if (window.TWEEN) {
            tweenAnimate.init({
                begin: { y: getScrollTop(target) },
                end: { y: 0 },
                easing: "Out",
                duration: 400,
                update: function (percent) {
                    scrollTop(target, this.y);
                }
            });
            tweenAnimate.animate();
        } else if (window.jQuery) {
            var selector = target === window ? "html,body" : target;
            $(selector).animate({ scrollTop: 0 }, 300);
        } else {
            scrollTop(target, 0);
        }
    }

    function scrollTop(target, y) {
        if (target === window) {
            window.scrollTo ? window.scrollTo(0, y) : document.body.scrollTop = y;
        } else {
            $(target)[0].scrollTop = y;
        }
    }

    function pullRefresh(container, callback, options) {
        var defaults = {
            id: 1,
            limit: 200,
            height: 50,
            text: "下拉刷新"
        };
        var settings = $.extend(defaults, options);
        var $container = $(container);
        var touch = { startY: 0, endY: 0 };
        var IsLoading = false, IsValid = false, IsMouseUpped = false;
        var $box = $(
            '<div id="pull-box" class="pull-box">' +
                '<div class="pull-item pull-text">' + settings.text + '</div>' +
                '<div class="pull-item pull-icon">' +
                    '<div class="loading-box loading-animate">' +
                        '<div class="loading-block"></div>' +
                        '<div class="loading-block"></div>' +
                        '<div class="loading-block"></div>' +
                        '<div class="loading-block"></div>' +
                        '<div class="loading-block"></div>' +
                        '<div class="loading-block"></div>' +
                    '</div>' +
                '</div>' +
            '</div>'
        );

        disableWechatWebviewSlide();

        if ($("#pull-box").length == 0) {
            $container.prepend($box);
        }

        $container.on("touchstart mousedown", function (e) {
            if (!e.touches) IsMouseUpped = false;
            var startY = getTouchClientY(e);
            touchStartHandler(startY);
        });
        $container.on("touchmove mousemove", function (e) {
            if (IsMouseUpped) return;
            var moveY = getTouchClientY(e);
            touchMoveHandler(moveY);
        });
        $container.on("touchend mouseup", function (e) {
            if (!e.touches) IsMouseUpped = true;
            var endY = getTouchClientY(e);
            touchEndHandler(endY);
        });

        function getTouchClientY(e){
            var touches = null;
            e = e.originalEvent ? e.originalEvent : e;
            touches = e.touches && e.touches.length > 0 ? e.touches : e.changedTouches;
            return touches ? touches[0].clientY : e.clientY;
        }

        function touchStartHandler(startY) {
            IsValid = $container[0].scrollTop <= 1;
            if (validate()) return;
            touch.startY = startY;
        }

        function touchMoveHandler(currentY) {
            if (validate()) return;
            touch.endY = currentY;
            if (touch.endY - touch.startY > 0 && !$("html").hasClass("noscroll")) {
                $("html").addClass("noscroll");
            }
            touchMoveY(touch.endY - touch.startY);
        }

        function touchEndHandler(endY) {
            if (validate()) return;
            touch.endY = endY;
            touch.move = touch.endY - touch.startY;
            $("html").removeClass("noscroll");
            rebound(touch.move);
            if (touch.move > settings.limit) {
                load();
            }
        }

        function getboxHeight() {
            return $(".pull-box .pull-item:visible").height();
        }

        function validate() {
            return !IsValid || IsLoading;
        }

        function touchMoveY(y) {
            setVendorAttr($container, "transform", "translate3d(0," + (y - y * 0.7) + "px,0)");
        }

        function rebound(move) {
            easeMove(move > settings.limit ? getboxHeight() : 0);
        }

        function easeMove(y, callback) {
            setVendorAttr($container, "transition", "transform 0.3s ease");
            $container.one("webkitTransitionEnd transitionend", function () {
                setVendorAttr($container, "transition", "none");
                callback && callback();
            });
            setTimeout(function () {
                setVendorAttr($container, "transform", "translate3d(0," + y + "px,0)");
            });
        }

        function load() {
            IsLoading = true;
            $container.addClass("pull-loading");
            callback && callback({ complete: complete });
        }

        function complete() {
            IsValid = false;
            IsLoading = false;
            easeMove(0, function () {
                $container.removeClass("pull-loading");
            });
        }
    }
    // scroll end

    // utils begin
    function setVendorAttr(target, name, value) {
        VENDOR_PREFIX.forEach(function (val, idx) {
            $(target).css(val + name, value);
        });
    }
    // utils end

    // tabs begin
    function bindTabsClick() {
        //$(".tabs").each(function () {
        //    $(".tabs>li").click(function () {
        //        var $this = $(this);
        //        $this.addClass("active").siblings(".active").removeClass("active");
        //        _toggleTabTarget($this);
        //    });
        //    _toggleTabTarget($(".tabs>li.active"));
        //});
        $(document).on("click", "[data-toggle='tabs']>li", function(){
            var $this = $(this);
            $this.addClass("active").siblings(".active").removeClass("active");
            toggleTabTarget($this);
        });
        toggleTabTarget($("[data-toggle='tabs']>li.active"));

        function toggleTabTarget($li) {
            $li.each(function () {
                var $this = $(this);
                var $target = $($this.attr("data-target"));
                $target.closest(".tab-targets").children(":visible").hide();
                $target.show();
            });
        }
    }
    // tabs end

    // head menu begin
    function bindHeadMenu() {

        var options = {
            selector: "body",
            className: "open-left-menu"
        };

        var _button = $('[data-action="open-left-menu"]');
        var _wrapper = document.querySelector('.wrapper');

        if (_button.length > 0 && _wrapper){

            $(_wrapper).prepend('<div class="wrapper-shade"></div>');

            _button.each(function(){
                $(this)[0].addEventListener("click", function (e) {
                    var $menu = $(this);
                    toggleHeadMenu(null, options);
                }, true);
            });

            _wrapper.addEventListener("click", function (e) {
                if ($(options.selector).hasClass(options.className)) {
                    toggleHeadMenu(null, options);
                    e.stopPropagation();
                    e.preventDefault();
                }
            }, true);
        }

        function toggleHeadMenu(status, options) {

            var $wrapper = $(options.selector);

            if (status) {
                if (status == "show") {
                    $wrapper.addClass(options.className);
                } else if (status == "hide") {
                    $wrapper.removeClass(options.className);
                }
            } else {
                $wrapper.toggleClass(options.className);
            }
        }
    }
    // head menu end

    // shopping cart begin
    function bindShoppingCart(options) {

        var defaults = {
            init: null,
            onadd: null,
            onsubtract: null,
            onchange: null
        };
        var settings = $.extend(defaults, options);

        initShoppingCart(settings);

        function initShoppingCart(settings) {
            var $box = $(".shopping-cart");
            $box.each(function () {
                var $current = $(this);
                var $input = $current.find('input');
                var $text = $current.find(".count");
                var hasText = !$input.hasClass(".count");

                if ($input.val() == "") {
                    $input.val(0);
                }

                var count = parseInt($input.val());
                hasText && $text.text(count);
            });
            fireShoppingCartEvent(settings, "init", this, getShoppingCartTotal());

            $(document).on("click", ".shopping-cart", function (e) {
                var $target = $(e.target);
                if ($target.attr("data-action") == "") return false;

                var $current = $(this),
                    $add = $current.find("[data-action='add']"),
                    $sub = $current.find("[data-action='sub']"),
                    $input = $current.find('input'),
                    $text = $current.find(".count"),
                    hasText = !$input.hasClass(".count"),
                    count = parseInt($input.val()),
                    total = null;

                if ($target.closest("[data-action='add']").length > 0 || $target.attr("data-action") == "add") {
                    count++;
                    $input.attr("value", count).val(count);
                    hasText && $text.html(count);
                    if (count > 0) {
                        $sub.css("display", "inline-block");
                        hasText && $text.css("display", "inline-block");
                    }
                    total = getShoppingCartTotal();
                    fireShoppingCartEvent(settings, "onadd", this, total);
                    fireShoppingCartEvent(settings, "onchange", this, total);
                }

                if ($target.closest("[data-action='sub']").length > 0 || $target.attr("data-action") == "sub") {
                    count--;
                    $input.attr("value", count).val(count);
                    hasText && $text.html(count);
                    if (count <= 0) {
                        $sub.hide();
                        hasText && $text.hide();
                    }
                    total = getShoppingCartTotal();
                    fireShoppingCartEvent(settings, "onsubtract", this, total);
                    fireShoppingCartEvent(settings, "onchange", this, total);
                }
            });
        }

        function getShoppingCartTotal() {
            var totalCount = 0, totalPrice = 0;
            $(".shopping-cart input[value]:not([value='0'])").each(function () {
                var count = $(this).attr("value") || $(this).val();
                var price = $(this).attr("data-price");
                count = isNaN(count) ? 0 : parseInt(count);
                price = isNaN(price) ? 0 : parseFloat(price);
                totalCount += count;
                totalPrice += price * count;
            });
            return { count: totalCount, price: totalPrice };
        }

        function fireShoppingCartEvent(settings, evt, thisObj, total) {
            settings.update && settings.update.call(thisObj, total);
            settings[evt] && settings[evt].call(thisObj, total);
        }

        function isFloat(number) {
            return /\d+\.\d+/.test(number);
        }
    }
    // shopping cart end

    // counter begin
    function Counter(container, count, options) {

        var defaults = {
            init: true,
            count: count,
            tick: null,
            print: null,
            complete: null,
            timespan: 1000,
            decrement: 1,
            toFixed: 0
        };
        var config = $.extend({}, defaults, options);
        //config.totalCount = count;

        var $container = $(container),
            clearId,
            status = 0;

        function init() {
            count = defaults.count;
            print();
        }

        function print() {
            var printText = config.print ? config.print(count) : count;
            $container.text(printText);
        }

        function decrement() {
            count = (count - config.decrement).toFixed(config.toFixed);
        }

        function start() {
            if (status == 1 || count <= 0) return;
            status = 1;
            clearTimeout(clearId);
            clearId = setInterval(function () {
                decrement();
                print();
                config.tick && config.tick(count);
                if (count <= 0) {
                    config.complete && config.complete.call($container);
                    clearInterval(clearId);
                }
            }, config.timespan);
        }

        function pause() {
            status = 0;
            clearInterval(clearId);
        }

        function reset() {
            count = defaults.count;
            pause();
            init();
        }

        config.init && init();

        return {
            start: start,
            pause: pause,
            reset: reset
        }
    }
    // counter end

    // timer begin
    function Timer(container, time, options) {
        var defaults = {
            format: "HH:mm:ss",
            tick: null,
            complete: null,
            timespan: 1000,
            print: function (count) {
                return formatTimeString(parseFloat((count * (this.timespan / 1000)).toFixed(3)), this.format);
            }
        };
        var config = $.extend(defaults, options);
        var timer = new Counter(container, timeStringToSecond(time) / (config.timespan / 1000), config);
        return timer;
    }

    function timeStringToSecond(formatted) {
        if (typeof formatted === "number") return formatted;
        var arr = formatted.split(":").reverse();
        var second = 0;
        for (var i = 0; i < arr.length; i++) {
            second += parseInt(arr[i]) * Math.pow(60, i);
        }
        return second;
    }

    function formatTimeString(second, formatted) {
        if (!formatted) formatted = "HH:mm:ss";
        var hour = 0, minute = 0, millisecond = 0;
        if (second >= 3600 && /HH/.test(formatted)) {
            hour = Math.floor(second / 3600);
            second = second % 3600;
        }
        if (second >= 60 && /mm/.test(formatted)) {
            minute = Math.floor(second / 60);
            second = second % 60;
        }
        if (/\./.test(second) && /ms/.test(formatted)){
            millisecond = parseInt(second.toString().split(".")[1] || 0);
            second = parseInt((second-1).toFixed(0));
        }
        return formatted.replace("HH", padLeftString(hour, 0, 2))
                         .replace("mm", padLeftString(minute, 0, 2))
                         .replace("ss", padLeftString(second, 0, 2))
                         .replace("ms", padLeftString(millisecond, 0, 2));
    }

    function buildString(char, count) {
        if (!count) count = 0;
        var result = "";
        for (var i = 0; i < count; i++) {
            result += char.toString();
        }
        return result;
    }

    function padLeftStr(str, char, count) {
        return buildString(char, count) + str.toString();
    }

    function padRightStr(str, char, count) {
        return str.toString() + buildString(char, count);
    }

    function padLeftString(str, char, length) {
        return buildString(char, length - str.toString().length) + str;
    }

    function padRightString(str, char, length) {
        return str + buildString(char, length - str.toString().length);
    }
    // timer end

    // dropdown begin
    function bindDropdownButton() {
        var $btnGroup = $();
        /*var Events = {
            onselected: []
        };*/
        $(document).on("click", "[data-toggle~='dropdown']", function (e) {
            $btnGroup = $(this).closest(".btn-group");
            $(".btn-group.open").not($btnGroup).removeClass("open");
            $btnGroup.toggleClass("open");
        });
        $(document).on("click", ".btn-group .dropdown>li", function () {
            if ($btnGroup.attr("role") === "combobox") {
                var $btnDown = $(".btn-group.open [data-toggle='dropdown']");
                var text = $(this).text(),
                    value = $(this).attr("data-value");
                $btnDown.text(text).attr("data-value", value);
                $btnDown.trigger("selected", [value, text]);
            }
            $btnGroup.removeClass("open");
        });
        $(document).on("click", "", function (e) {
            if ($(e.target).closest(".btn-group")[0] != $btnGroup[0]) {
                $btnGroup.removeClass("open");
            }
        });
    }
    // dropdown end

    // switch begin
    function bindSwitch() {
        $(document).on("click", "[data-toggle-class]", function (e) {
            var $target = $($(this).attr("data-target") || this),
                className = $target.attr("data-toggle-class"),
                groupName = $target.attr("data-group"),
                defaultClass = $target.attr("data-default-class");
            if (groupName){
                $("[data-group='" + groupName + "']." + className).removeClass(className);
                $target.addClass(className);
            } else if (defaultClass) {
                $target.hasClass(defaultClass)
                    ? $target.removeClass(defaultClass).addClass(className)
                    : $target.removeClass(className).addClass(defaultClass);
            } else {
                $target.toggleClass($(this).attr("data-toggle-class"));
            }
        });
        $(document).on("click", "[data-toggle-text]", function () {
            var $target = $($(this).attr("data-target") || this);
            var defaultText = $target.attr("data-default-text") || $target.text();
            var toggleText = $target.attr("data-toggle-text");
            if (!$target.attr("data-default-text")) $target.attr("data-default-text", defaultText);
            $target.text() === defaultText ? $target.text(toggleText) : $target.text(defaultText);
        });
    }
    // switch end

    // emotion begin
    function Emoticon() {
        
        var that = {};
        that.Config = null;

        function loadConfig(callback) {
            if (!that.Config) {
                loadFromStorage(callback);
            } else {
                callback && callback(that.Config);
            }
        }

        function loadFromStorage(callback) {
            var key = "bigger.front.emoticon";
            if (window.localStorage) {
                that.Config = JSON.parse(localStorage.getItem(key));
                if (!that.Config) {
                    requestEmoticonConfig(key, callback);
                } else {
                    callback && callback(that.Config);
                }
            } else if (!that.Config) {
                requestEmoticonConfig(key, callback);
            }
        }
        function requestEmoticonConfig(key, callback) {
            $.get(
                "/Content/LMS/component/emoticon/config.txt?v=1",
                function (text) {
                    text = text.replace(/\s+/g, " ");
                    that.Config = JSON.parse(text);
                    localStorage.setItem(key, text);
                    callback && callback(that.Config);
                }
            );
        }

        function loadHtml(config) {
            $.get(
                config.Path + config.Home + "?v=" + Math.random(),
                function (data) {

                    appendHtml(data, config);

                    var slideWidth = 308;
                    var openEmoClass = "open-emoticon";
                    var $body = $("body");
                    var $main = $(".component-emoticon");
                    var $container = $("[data-emoticon-element='container']").width(slideWidth);
                    var $button = $main.find(".btn-emoticon");
                    var $input = $($button.data("input"));

                    setPosition($container, slideWidth);

                    $button.click(function () {
                        $body.toggleClass(openEmoClass);
                        if ($body.hasClass(openEmoClass)) {
                            //$container[0].scrollIntoView && $container[0].scrollIntoView();
                        }
                    });
                    $body.on("click", "[data-dismiss~='emoticon']", function () {
                        $body.removeClass(openEmoClass);
                        var $input = $($(this).data("clear"));
                        if ($input.length > 0) {
                            $input.val("");
                        }
                    });
                    //选择表情
                    $container.on("click", "a", function (e) {
                        var em = $(this).attr("title");
                        if (em == "") {
                            $input.val($input.val().replace(/\[[^\]]*\]$/, ""));
                        } else {
                            $input.val($input.val() + "[" + em + "]");
                        }
                    });
                    //滑动
                    var mySwiper = new Swiper("[data-emoticon]", {
                        width: slideWidth,
                        pagination: ".emoticon-swiper-pagination .pagination-wrapper"
                    });
                }
            );
        }

        function appendHtml(data, config) {
            if ($("[data-emoticon-container]").length == 0) {
                var fileName = "";
                data = data.replace(/<link.*?>/g, function(value, index, obj){
                    fileName = value.match(/[^\/]*\.css/);
                    return "";
                });
                $("head").append("<link href='" + config.Path + "css/" + fileName + "' rel='stylesheet' />");
                $("[data-part='emoticon']").html(data);
            }
        }

        function setPosition(container, slideWidth) {
            var $container = $(container);
            var rect = getComputedRect($container);
            var rect1 = getComputedRect($("[data-part='emoticon']"));
            $container.css({
                position: "relative",
                width: document.documentElement.clientWidth,
                left: -rect.left
            });
        }

        function load(button) {
            loadConfig(function (config) {
                loadHtml(config);
            })
        }

        function replace(content) {
            content = content || "";
            if (!that.Config) {
                console.log("表情配置文件未加载");
                return;
            }
            var regex = /\[.*?\]/g;
            return content.replace(regex, function (word) {
                return "<img class='em' width='25' src='" + that.Config.Path + "mp/" + that.Config.Data[word] + ".gif'/>"
            });
        }

        this.Load = load;
        this.LoadConfig = loadConfig
        this.Replace = replace;
    }
    // emotion end

    // disabled wechat scroll begin
    function disableWechatWebviewSlide() {
        var container = getScrollTarget();
        if (DEVICE.iPhone){
            $(container).addClass("disabled-wechat-slide");
            scrollTop(container, 1);
            bindScrollEvent(container);
        }
    }
    // disabled wechat scroll end

    // utils begin
    function getHiddenParents(element){
        var hiddenParents = [];
        $(element).parents().each(function(){
            if ($(this).css("display") == "none"){
                hiddenParents.push(this);
            }
        });
        return hiddenParents;
    }
    function getComputedRect(element, selector){
        var rect = {};
        var targetElement = selector ? $(element).find(selector)[0] : $(element)[0];
        if (targetElement){
            renderHiddenElement(element, function(){
                if (this.getBoundingClientRect){
                    rect = this.getBoundingClientRect();
                } else {
                    rect = {
                        width: $(this).width(),
                        height: $(this).height(),
                        top: this.offsetTop,
                        left: this.offsetLeft
                    };
                    rect.right = rect.left + rect.width;
                    rect.bottom = rect.top + rect.height;
                }
            });
        }
        return rect;
    }

    function renderHiddenElement(element, callback){
        var $element = $(element);
        var hiddenParents = getHiddenParents($element);
        hiddenParents.push($element);
        $(document.head).append('<style>.render-hidden-element{ visibility: hidden !important; position: absolute !important; display: block !important; }</style>');
        hiddenParents.forEach(function(item, index, obj){
            $(this).addClass("render-hidden-element");
        });
        callback && callback.call($element[0]);
        hiddenParents.forEach(function(item, index, obj){
            $(this).removeClass("render-hidden-element");
        });
    }

    function fitView() {

        var $view = $("body"),
            $wrap = $(".wrapper"),
            viewWidth = $view.width(),
            viewHeight = $view.height(),
            wrapWidth = $wrap.width(),
            wrapHeight = $wrap.height(),
            scale = 1;

        if (viewWidth > viewHeight) {
            scale = viewHeight / wrapHeight;
        } else {
            scale = viewWidth / wrapWidth;
        }

        $("[role='viewport']").css({
            "-webkit-transform-origin": "center center",
            "transform-origin": "center center",
            "-webkit-transform": "scale3d(" + scale + "," + scale + "," + scale + ")",
            "transform": "scale3d(" + scale + "," + scale + "," + scale + ")"
        });
    }
    // utils end

    return {
        Timer: Timer,
        Counter: Counter,
        InitAppraise: initAppraise,
        BindBackToTop: bindBackToTop,
        RecordScrollTop: recordScrollTop,
        BindTabsClick: bindTabsClick,
        BindHeadMenu: bindHeadMenu,
        //BindThemeSystem: bindThemeSystem,
        BindShoppingCart: bindShoppingCart,
        PadLeftStr: padLeftStr,
        PadRightStr: padRightStr,
        PadLeftString: padLeftString,
        PadRightString: padRightString,
        FormatTimeString: formatTimeString,
        BindDropdownButton: bindDropdownButton,
        GetScrollTarget: getScrollTarget,
        GetScrollTop: getScrollTop,
        ScrollTop: scrollTop,
        TweenAnimate: tweenAnimate,
        BindSwitch: bindSwitch,
        PullRefresh: pullRefresh,
        Emoticon: new Emoticon(),
        //DisableWechatWebviewSlide: disableWechatWebviewSlide,
        FitView: fitView
    }
})();


// prototype extend
(function(){

    String.prototype.toInt = function(){
        return parseInt(this.match(/\d+/));
    };

    String.prototype.toFloat = function(){
        return parseFloat(this.match(/\d+.\d+/));
    };

    String.prototype.padLeft = function (char, length) {
        return Global.PadLeftString(this, char, length);
    };

    String.prototype.padRight = function (char, length) {
        return Global.PadRightString(this, char, length);
    };

    /*Array.prototype.forEach = function(callback){
        for (var i=0; i<this.length; i++){
            callback && callback.call(this[i], this[i], i, this)
        }
    };*/

    Date.prototype.format = function (formatter) {

        var _this = this,
            year = _this.getFullYear().toString(),
            month = (_this.getMonth() + 1).toString(),
            day = _this.getDate().toString(),
            hour = _this.getHours().toString(),
            minute = _this.getMinutes().toString(),
            second = _this.getSeconds().toString();

        var process = function (data, match, length) {
            if (!length) length = 0;
            var end = data.length > 1 ? 0 : data.length - match.length;
            return data.substring(data.length, end).padLeft("0", length);
        };

        var formatted = formatter.replace(/y+/g, function (match) {
            return year.substring(year.length, year.length - match.length);
        }).replace(/M+/g, function (match) {
            return process(month, match, match.length);
        }).replace(/d+/g, function (match) {
            return process(day, match, match.length);
        }).replace(/H+/g, function (match) {
            return process(hour, match, 2);
        }).replace(/m+/g, function (match) {
            return process(minute, match, 2);
        }).replace(/s+/g, function (match) {
            return process(second, match, 2);
        });

        return formatted;
    }

})();

// DOM ready
$(function () {
    window.FastClick && FastClick.attach(document.body);
    //Global.DisableWechatWebviewSlide();
    Global.BindDropdownButton();
    Global.BindTabsClick();
    Global.BindHeadMenu();
    Global.BindSwitch();
});